#undef  xuser
#define xuser mixc::talk_about_dual_way_barrier::inc
#include"concurrency/lock/atom_load.hpp"
#include"concurrency/lock/atom_store.hpp"
#include"concurrency/lock/atom_sub.hpp"
#include"concurrency/lock/dual_way_barrier.hpp"
#include"concurrency/thread.hpp"
#include"concurrency/thread_self.hpp"
#include"macro/xhint.hpp"
#include"mixc.hpp"

xinit(xuser::the_main){
    using namespace xuser;

    dual_way_barrier barrier;
    uxx rest            = 32;
    uxx k               = rest;
    uxx counter[16]     = {};

    // 由于 thread lambda 是值传递，所以需要传指针类型才能读到同同一块内存
    auto ptr_counter    = counter;
    auto ptr_barrier    = xmodify(barrier);
    auto ptr_rest       = xmodify(rest);
    auto ptr_k          = xmodify(k);

    // 获取主线程 id
    auto id             = thread_self::id();

    for(uxx i = 0, end = rest; i < end; i++){
        thread(xdetached{
            if (atom_sub(xmodify(*ptr_k), 1) == 0){
                xhint("begin");
            }

            for(uxx j = 0; j < 10000000; j++){
                // 一共分 16 组，每组 16 个成员，相同组之间可以并发访问
                // 每一组第 i 个成员操作 counter[i]
                ptr_barrier->lock(i >> 4 ? dual_way_channel0 : dual_way_channel1, [&](){
                    // 这里为了避免 cpu cache 导致值不一致，使用了原子加载/存储操作
                    // 同时这里模拟线程不安全的读改写模式，用于检验此 lock 是否真的有效做了并发同步
                    auto value  = atom_load(xmodify(ptr_counter[i & 0xf]));
                    value      += 1;
                    atom_store(xmodify(ptr_counter[i & 0xf]), value);
                });
            }

            // 当所有线程完成时唤醒主线程
            if (atom_sub(xmodify(*ptr_rest), 1) == 0){
                thread_self::resume(id);
            }

            xhint(*ptr_rest, i);
        });
    }

    thread_self::suspend();

    for(uxx i = 0; i < 16; i++){
        auto value = atom_load(xmodify(counter[i]));
        xhint(i, value);
    }
};
